home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 25
/
Cream of the Crop 25.iso
/
games
/
dcg408up.zip
/
EXAMPLE
/
CONTROL.SCR
< prev
next >
Wrap
Text File
|
1997-03-03
|
65KB
|
2,166 lines
!
! CONTROL.SCR
!
! This script manages some independent functions of the game system. The
! script is called by the game driver at certain points during game play,
! and the entry points are numeric (@0, @1, @2..) instead of the usual entry
! points (@TALK, @GET, ..).
!
! QUICK SUMMARY OF ENTRY POINTS:
!
! :@0 - Time Control. Executed once every minute of game time.
! (See 'MOVES_PER_MINUTE' parameter)
!
! :@1 - PLAYER MOVES Invoked ONCE for EACH player during a FIGHT
!
! :@2 - MONSTER MOVES Invoked ONCE ONLY to move ALL monsters (at
! once) during a FIGHT.
!
! :@3 - Keyboard/Mouse Event. MAIN EVENT HANDLER. Called for every key
! pressed or mouse button clicked during
! normal game play.
!
! :@4 - POSITION MONSTER Called ONCE ONLY when STARTING a fight.
! The array of NPCs (foreach NPC do..) is
! the set of expanded monsters from the
! original monster being fought. They all
! have the same X/Y position and need to
! be "spread out" for fighting
!
! :@5 - NPC MOVES Called ONCE after every @3 call, this
! entry point allows you to animate the
! NPCs in the game. In general, it's a bad
! idea to try to animate too many NPCs. It's
! main purpose at this time is to allow for
! HOSTILE npc animation under script control.
!
! LAST MOD. BY DESCRITPION
! 10-15-95 D. Hernandez First release for DCGAMES Version 4.0
! 11-15-95 D. Hernandez Added hidden/locked landscape door handling
!
!
!---------------------------------------------------------------------------!
:@0 ! Entry Point @0 : Time Control Script !
!---------------------------------------------------------------------------!
!
! This script will start execution at this label once per 'minute' during
! regular play. The variable GROUP.MOVES contains the total number of
! moves the party has made since the begining of the game. A minute is
! defined by the current value of the variable 'MovesPerMinute'
!
! Time is controled by seting the following variables from any script:
!
! Variable Default Description
! ------------------- ------- --------------------------------
! MovesPerMinute 2 # of moves per game 'minute'
! MinutesInAnHour 60 # of minutes in an game 'hour'
! HoursInADay 24 # of hour in a game 'day'
! DaysInAMonth 30 # of days in a game 'month'
! MonthsInAYear 12 # of months in a game 'year'
!
! The CURRENT time is obtained (and modified) by setting the following
! variables:
!
! year Current Year (Range -32767 to 32767)
! month Current Month (Range 0 to MonthsInAYear - 1)
! day Current Day (Range 0 to DaysInAMonth - 1)
! hour Current Hour (Range 0 to HoursInADay - 1)
! minute Current Minute (Range 0 to MinutesInADay - 1)
!
! Update the clock, one more minute has passed !
gosub CLOCK_TICK;
if minute = 0 gosub CLOCK_PRINT;
! No perform some time dependent actions
! First, save our original status just in case we need it later..
L255 = group.current; ! Save current party spokesperson !
L254 = FALSE; ! Have NOT created a random monster !
! THINGS TO DO EVERY MINUTE
if group.energy > 0 then
dec( group.energy );
! In the desert, during the day, you consume energy twice as fast
if world.density(group.x,group.y) = DESERT and group.vehicle.count = 0 then
if hour > sunrise and hour < sunset then
dec( group.energy );
endif;
endif;
if L2 = SWAMP and group.vehicle.count = 0 then
if random(5) = 0 then ! one out of 5 !
L255 = group.current;
foreach player do
if not player.poisoned then
player.poisoned = (random(3) = 0); ! one out of 3 !
if player.poisoned then
writeln( player.name, " got poisoned by swamp gas!" );
endif;
endif;
endfor;
group.current = L255; ! Restore the current spokesperson !
endif;
endif;
endif;
! THINGS TO DO ONCE AN HOUR
if minute = 0 then
! Create a random monster 1 out of every 5 times (approx) !
if random(5) = 0 then
if world.type = OUTDOORS or world.type = DUNGEON or world.type = HAUNTED then
gosub NEWMONSTER;
endif;
endif;
! Check to see if you have food.. !
if group.food <= group.size then
if group.food = 0 then
writeln( "You have no food.." );
else
writeln( "You are running out of food.." );
endif;
endif;
endif;
! Every quarter of an hour !
L25 = max(MinutesInAnHour / 4 + 1,2);
if minute % L25 = 0 then
! Group must rest within 2 hours or start suffering damage !
if group.energy < MinutesInAnHour * 2 then
if group.energy > 0 then
writeln( "You must rest soon.." );
else
writeln( "You are exhausted.." );
endif;
endif;
! Check for poison, hunger and exhaustion !
foreach player do
if player.hp > 0 then
if player.poisoned then
s0 = "poisoning";
gosub HITPLAYER;
elsif player.energy = 0 and group.food = 0 then
s0 = "hunger";
gosub HITPLAYER;
elsif group.energy <= 0 then
s0 = "exhaustion";
gosub HITPLAYER;
endif;
endif;
endfor;
endif;
!
! The following controls healing and recovery of power. You can
! change the rate of healing by using a different value, but remember
! that the power heal value (8 below) should be a MULTIPLE of the
! first number (4) or it will not work.
!
if minute % 4 = 0 and group.energy > 0 then
foreach player do
if group.food or player.energy then
gosub HEAL_HP;
! Every 8 (twice as slow) restore power
if minute % 8 = 0 then
gosub HEAL_PWR;
endif;
endif;
endfor;
endif;
! Go back with same selected spokesperson.. !
group.current = L255;
CONTINUE;
!---------------------------------------------------------------------------!
:@1 ! PLAYER MOVES DURING A FIGHT
!---------------------------------------------------------------------------!
!
frame(player.x,player.y,SYS_FRAME);
write( player.name, " - " );
if player.hp < 2 then
if player.hp = 1 then writeln( "is unconscious!" );
else writeln( "is dead!" );
endif;
elsif player.paralyzed then
writeln( "is paralyzed!" );
elsif player.scared then
writeln( "is scared!" );
else
stats(player);
keypress = GET_ACTION;
frame(player.x,player.y,-SYS_FRAME);
goto :@3;
endif;
frame(player.x,player.y,-SYS_FRAME);
STOP;
!---------------------------------------------------------------------------!
:@2 ! Move NPCs during a fight
!---------------------------------------------------------------------------!
runscript( "FIGHTING", 1 );
stop;
!---------------------------------------------------------------------------!
:@4 ! Position NPCs before a fight
!---------------------------------------------------------------------------!
runscript( "FIGHTING", 0 );
stop;
!---------------------------------------------------------------------------!
:@5 ! Animate NPCs (called after every call to @3) Except during a fight
!---------------------------------------------------------------------------!
foreach visible npc do
if npc.type = HOSTILE then
! Every 2nd move, if the NPC can see the player, they follow !
if group.moves % 2 = 0 and los( npc, group ) then
L3 = group.x - npc.x;
L4 = group.y - npc.y;
if abs(L3) > npc.weapon.range or ! Are we within the NPC's
abs(L4) > npc.weapon.range then ! .. range?
L3 = sgn(L3); L0 = npc.x + L3; ! NO, move npc towards the
L4 = sgn(L4); L1 = npc.y + L4; ! .. player (one step only)
L2 = 0; ! set NPC moving Flag
L22 = npc.index;
gosub CHK_A_MOVE; ! Call movement routine
if npc.index <> L22 then
npc.index = L22;
endif;
if NOT L2 then ! Can't move, try to move around the obstacle !
L3 = group.x - npc.x;
L4 = group.y - npc.y;
if L3 > L4 then !
L3 = sgn(L3); L0 = npc.x + L3; ! Move one step in this...
L4 = 0; L1 = npc.y; ! .. direction...
else
L3 = 0; L0 = npc.x; ! Move one step in this...
L4 = sgn(L4); L1 = npc.y + L4; ! .. direction...
endif;
L2 = 0; ! NPC moving again..
L22 = npc.index;
gosub CHK_A_MOVE; ! Call movement routine
if npc.index <> L22 then
npc.index = L22;
endif;
endif;
if L2 then ! Move IT !
npc.x = L0;
npc.y = L1;
endif;
else
voice( "ALERT", 1000 );
writeln( "The ", npc.name, " attacks!" );
FIGHT;
endif;
endif; ! los() !
else ! not-hostile !
if npc.block <> npc.block2 then
L0 = npc.block;
npc.block = npc.block2;
npc.block2 = L0;
else
! OPTIONAL: If DCPEOPLE.VHx has TWO consecutive tiles per character
! if npc.block % 2 = 0 then
! inc( npc.block );
! else
! dec( npc.block );
! endif;
endif;
endif;
endfor; ! visibile npcs !
if player.block <> player.block2 then
L0 = player.block;
player.block = player.block2;
player.block2 = L0;
else
! if player.block % 2 = 0 then
! inc( player.block );
! else
! dec( player.block );
! endif;
endif;
stop;
!---------------------------------------------------------------------------!
:@3 ! Keyboard Map Entry Point : Process a key press
!---------------------------------------------------------------------------!
!
! THE FOLLOWING TABLE IS A SHORT LIST OF THE VALUES ASSOCIATED WITH EACH
! KEY. NOTE THAT SPECIAL KEYS HAVE BEEN MAPPED TO DISTINCT NUMBERS TO
! AVOID USING THE WIERD PC KEY VALUES.
! CTRL +A to Z = 1 to 26
! ESCape key = 27
! space = 32
! 0-9 = 48 to 57
! A-Z = 65 to 90
! a-z = 65 to 90 (i.e. NO LOWERCASE)
! F1 - F10 = 131 to 140
! Shift+F1 - F10 = 141 to 150
! Ctrl +F1 - F10 = 151 to 160
! ALT +F1 - F10 = 161 to 170
! ALT +1 to 10 = 171 to 180
! ALT +A to Z = 201 to 226
!
! KEY PAD VALUES (arrow keys!):
! HOME = 190 ! CTRL + HOME = 187
! END = 191 ! CTRL + END = 186
! UP = 192 ! CTRL + UP = 230
! DOWN = 193 ! CTRL + DOWN = 231
! LEFT = 194 ! CTRL + LEFT = 184
! RIGHT = 195 ! CTRL + RIGHT = 185
! PGUP = 196 ! CTRL + PGUP = 189
! PGDN = 197 ! CTRL + PGDN = 188
! INS = 198
! DEL = 199
!
! When you use the mouse to click on something, the variable BUTTON
! contains which button you clicked (1=Left, 2=Right, 3=Middle), and
! the rest of the information is obtained as follos:
!
! VALUE OF KEYPRESS Value of POINTX Value of POINTY
! ----------------- ------------------ ------------------
! VIEW_CLICK 235 World X coordinate World Y coordinate
! MENU_CLICK 236 Menu Offset Menu Choice (0 to n)
! ICON_CLICK 237 0-7 icon position 0-n block # in DCSYSTEM.VH1
! STAT_CLICK 238 6 (group was shown) 0-n (group member clicked)
! CHAR_CLICK 239 0-n (current player) Clicked Item (in LIST)
! 0 = nothing particular
! 1 = weapon
! 2 = shield
! 3 = armor
! 4 = staff
! 5 = ring
! 6 = amulet
! BODY_CLICK 240 0-n (current player) Clicked Item
! 0 = nothing particular
! 1 = Hand One (weapon)
! 2 = Hand Two (Shield/Staff)
! 3 = Torso (Armor)
! 4 = Waist (Belt)
! 5 = Legs (Leggings/pants)
! 6 = Feet (shoes)
! 7 = Head (hat/helmet)
! 8 = Neck (necklace/amulet)
! 9 = Finger One (ring)
! 10 = Finger Two (ring)
! PACK_CLICK 241 0-n (current player) 0-15 (Item # in backpack)
! MNAV_CLICK 242 0-5 mnav button 0-n block # in DCSYSTEM.VHx
!
if KEYPRESS = 27 then
if fighting then
writeln( "Trying to escape.." );
fight( STOP );
! You could call 'runscript( "FIGHTING", 2 )' if
! You wanted too. Or even 'runscript( "FIGHTING", 6 )' for
! all I care, if you wanted to have an @6 entry point for
! handling fights.
STOP;
endif;
endif;
if KEYPRESS >= 65 and KEYPRESS <= 90 then
on KEYPRESS - 65 goto
LETTER_A, LETTER_B, LETTER_C, LETTER_D, LETTER_E,
LETTER_F, LETTER_G, LETTER_H, LETTER_I, LETTER_J,
LETTER_K, LETTER_L, LETTER_M, LETTER_N, LETTER_O,
LETTER_P, LETTER_Q, LETTER_R, LETTER_S, LETTER_T,
LETTER_U, LETTER_V, LETTER_W, LETTER_X, LETTER_Y, LETTER_Z;
endif;
if KEYPRESS >= 48 and KEYPRESS <= 57 then
on KEYPRESS - 48 goto
DIGIT_0, DIGIT_1, DIGIT_2, DIGIT_3, DIGIT_4,
DIGIT_5, DIGIT_6, DIGIT_7, DIGIT_8, DIGIT_9;
endif;
if KEYPRESS = 32 goto SPACE;
! KEYPAD ARROWS !
if KEYPRESS >= 190 and KEYPRESS <= 197 then
on KEYPRESS - 190 goto
MOVE_UL, MOVE_DL, MOVE_UP, MOVE_DN, MOVE_LF, MOVE_RT, MOVE_UR, MOVE_DR;
endif;
if KEYPRESS >= 201 and KEYPRESS <= 226 then
! <ALT> + letter
if KEYPRESS = 222 goto ALT_V; ! Set the VOLUME !
CONTINUE;
endif;
if KEYPRESS >= 235 and KEYPRESS <= 242 then
on KEYPRESS - 235 goto
VIEW_CLICK, MENU_CLICK, ICON_CLICK, STAT_CLICK,
CHAR_CLICK, BODY_CLICK, PACK_CLICK, MNAV_CLICK;
endif;
! F1 - F10 = 131 to 140
if keypress >= 131 and keypress <= 140 then
on keypress - 131 goto FKEY1,FKEY2,FKEY3,FKEY4,FKEY5,FKEY6,FKEY7,FKEY8,FKEY9,FKEY10;
endif;
! Not handled by the script. The driver takes the default action !
CONTINUE;
:DIGIT_0
paint( SMALL );
STATS( group ); ! Display GROUP statistics !
STOP;
:DIGIT_1 :DIGIT_2 :DIGIT_3 :DIGIT_4 :DIGIT_5 :DIGIT_6
GROUP.CURRENT = KEYPRESS - 49; ! Use 0 to 5 instead of 1 to 6 !
STATS( GROUP.CURRENT ); ! Display INDIVIDUAL statistics !
STOP;
:DIGIT_7
stats( PREV );
STOP;
:DIGIT_8
stats( NEXT );
STOP;
:DIGIT_9
STOP;
:LETTER_A
write( "Attack: " );
L3 = locate;
if failure goto NOTHING;
! Attack a character !
if npc.count and npc.x = pointx and npc.y = pointy then
writeln( npc.class );
if fighting then
goto ATTACK_NPC; ! if we ARE fighting, go do it.. !
else
if npc.type <> HOSTILE then
writeln( "Find some bad guys to fight!" );
STOP;
endif;
endif;
FIGHT; ! START FIGHT MODE. SCRIPT EXECUTION ENDS HERE !
elsif object.count then
if object.type = CHEST then
if object.locktype then
writeln( "Instead of fighting it, try 'UNLOCK'!" );
else
writeln( "It's not even locked, why fight it?" );
endif;
else
writeln( "Why would you want to fight the ", object.name );
endif;
endif;
STOP;
:LETTER_B
stats( player.body );
STOP;
!------------------------------------------------------------------------!
:LETTER_C ! CAMP OUT !
!
! First, all temporary magical effects are eliminated by reducing any
! attribute that exceeds the maximum value for the same attribute.
!
! Armor, Shields, Rings and Amulets re-apply their effect (if any).
!
! The group rests for a third of a day, in one hour increments. For
! each hour rested, the group gains 4 hours of 'wake-up' energy. This
! means the group should be able to go one and a third days without
! sleep.
!
! Random monsters may appear, but not too often.
!
if fighting then
writeln( "This is not a good time to rest.." );
stop;
endif;
frame( group.x, group.y, 10 ); ! ZZZZ.... !
write( "Resting" );
voice( "snore", 1000 );
L255 = group.current; ! Save current party spokesperson !
L254 = FALSE; ! Have NOT created a random monster !
foreach player do
if player.hp > 0 then
gosub NEW_LEVEL; ! Figure out if character went up one level !
write(".");
! First, get rid of temporary magical increases in attributes !
player.str = min(player.str,player.mstr);
player.aim = min(player.aim,player.maim);
player.dex = min(player.dex,player.mdex);
player.spd = min(player.spd,player.mspd);
player.pwr = min(player.pwr,player.mpwr);
player.hp = min(player.hp, player.mhp);
player.iq = min(player.iq, player.miq);
player.ac = min(player.ac, player.mac);
if player.armor.count or player.shield.count then
if player.armor.cursed or player.shield.cursed then
player.ac = 0;
else
inc( player.ac, player.armor.ac + player.shield.ac );
endif;
endif;
if player.ring.count and player.ring.charges then
curritem = player.ring;
gosub M1_INVOKE;
endif;
if player.amulet.count and player.amulet.charges then
curritem = player.amulet;
gosub M1_INVOKE;
endif;
endif; ! Dead !
endfor; ! foreach player !
! # of hours to rest is one third of a day !
for L253 = 1 to HoursInADay / 3 + 1 do
write(".");
! Each hour of sleep gives 4 hours of energy !
if group.energy + MinutesInAnHour * 4 > 32767 then
group.energy = 32767;
else
inc( group.energy, MinutesInAnHour * 4 );
endif;
for L252 = 0 to MinutesInAnHour / 2 do
gosub CLOCK_TICK;
gosub CLOCK_TICK;
foreach player do
if group.food or player.energy then
gosub HEAL_HP;
if L252 % 2 then
gosub HEAL_PWR;
endif;
endif;
endfor;
endfor;
! Check to see if random monsters appear !
if world.type = OUTDOORS or world.type = DUNGEON or world.type = HAUNTED then
if random(17) = 0 then
gosub NEWMONSTER;
if L254 then
frame( group.x, group.y, -1 ); ! Restore !
writeln( "You wake up under attack.." );
FIGHT; ! Wake up and fight.. !
endif;
endif;
endif;
endfor;
group.current = L255; ! Go back to original spokes person !
frame( group.x, group.y, -1 ); ! Restore !
voice( "CHIMES", 1000 );
gosub CLOCK_PRINT;
STOP;
:LETTER_D
L0 = split;
stats( player.bp ); ! Show player's backpack !
paint(SMALL); ! Now.. (in case it was small) !
write( "Drop " );
L1 = getaction;
if not L0 then paint(LARGE); endif;
if L1 = 241 then
if point_y >= 0 then
setbp( player, pointy );
if player.bp.count then
curritem = player.bp;
runscript( curritem.script, "CURRITEM", DROP );
endif;
endif;
endif;
! OLD SCRIPT ...
! L0 = select$n( player );
! if L0 >= 0 then
! writeln( player.bp.name );
! runscript( player.bp.script, "CURRITEM", DROP );
! endif;
writeln( "nothing.." );
STOP;
:LETTER_E
if group.vehicle.count then ! Must be on foot !
writeln( "You must be on foot to enter/exit worlds.." );
STOP;
endif;
if group.x <> 0 or group.y <> 0 then
for L0 = 0 to 31 do
if world.doorx(L0) = group.x and world.doory(L0) = group.y then
world.door = L0; ! Use this door !
writeln( "Please wait..." );
runscript( WORLD, "WORLDDEF", EXIT );
! Should not return !
endif;
endfor;
endif;
writeln( "There is no door here.." );
STOP;
:LETTER_F
STOP;
:LETTER_G
! Get !
if player.hp > 1 then
write( "Get " );
L0 = locate( object ); ! Find OBJECT only, no people !
if success then
writeln( object.type );
if L0 < 2 then
runscript( object.script, "OBJECT", GET );
! Does NOT return !
else
writeln( "You can't reach the ", object.type );
endif;
else
goto NOTHING;
endif;
else
write( player.name, " can't get anything.." );
endif;
STOP;
:LETTER_H
STOP;
:LETTER_I
stats( player.bp ); ! Display Inventory, was -> display$n( player ); !
paint( SMALL );
STOP;
:LETTER_J
STOP;
:LETTER_K
STOP;
:LETTER_L
write( "Look at " );
L0 = locate; ! Find ANYTHING !
if success then
if npc.count and npc.x = pointx and npc.y = pointy then ! Found an NPC !
writeln( npc.type );
runscript( npc.script, "OBJECT", LOOK );
endif;
writeln( object.type );
runscript( object.script, "OBJECT", LOOK );
endif;
if world.density(pointx,pointy) = LOCKED_DOOR then
writeln( "locked door." );
writeln( "You see a locked door." );
stop;
endif;
if world.density(pointx,pointy) = HIDDEN_DOOR then
writeln( "wall." );
if abs(pointx - player.x) > 2 or abs(pointy - player.y) > 2 then
writeln( "You must get closer to the wall." );
else
world.block(pointx,pointy) = world.block(pointx,pointy) - 1;
writeln( "You found a hidden door!" );
endif;
stop;
endif;
goto NOTHING;
:LETTER_M
if group.size > 1 then
L0 = select$n( player.bp ); ! Select BP item ($n=show counts)
if L0 >= 0 then ! Did you choose something
L2 = group.current; ! Save current player index !
L1 = select( group ); ! Select a destination player !
if L1 >= 0 and L1 <> L2 then ! Did choose one !
group.current = L2; ! Restore original player !
setbp( player, L0 ); ! Select backpack item to move !
move( player.bp, player(L1) ); ! Move it !
stats; ! Refresh whatever is shown !
endif;
endif;
endif;
STOP;
:LETTER_N
write( "Invoke " );
L0 = select$n( player, SCROLL, GEMS );
stats;
if L0 >= 0 then
runscript( player.bp.script, "CURRITEM", INVOKE );
! Does NOT return !
endif;
writeln( "nothing .." );
if L0 < -1 then
writeln( "You have no items that you can invoke.." );
endif;
STOP;
:LETTER_O
STOP;
:LETTER_P
STOP;
:LETTER_Q
write( "Quaff (eat or drink) " );
L0 = select$n( player, FOOD, POTION );
stats;
if L0 >= 0 then
runscript( player.bp.script, "CURRITEM", INVOKE );
! Does NOT return !
endif;
writeln( "nothing .." );
if L0 < -1 then
writeln( "You have no items that you can eat or drink" );
endif;
STOP;
:LETTER_R
write( "Remove " );
L0 = select( player.body ); ! Any worn item !
if L0 >= 0 then
runscript( player.body.script, "CURRITEM", REMOVE );
endif;
stats;
writeln( "nothing.." );
if L0 < -1 then
writeln( "You have no items to remove!" );
endif;
STOP;
:LETTER_S
runscript( player.script, "CASTING", CAST );
STOP;
:LETTER_T
write( "Talk to " );
L0 = locate; ! Find ANYTHING !
if success then
if npc.count and npc.x = pointx and npc.y = pointy then ! Found an NPC !
if abs(npc.x - player.x) > 2 or abs(npc.y - player.y) > 2 then
writeln( "You must get closer!" );
STOP;
endif;
writeln( npc.type );
runscript( npc.script, "OBJECT", TALK );
endif;
if abs(object.x - player.x) > 2 or abs(object.y - player.y) > 2 then
writeln( "You must get closer!" );
STOP;
endif;
writeln( object.type );
runscript( object.script, "OBJECT", TALK );
endif;
if group.x = pointx and group.y = pointy then
writeln( "yourself..?" );
else
writeln( "no one.." );
endif;
STOP;
:LETTER_U
write( "Use/Unlock " );
L0 = locate( OBJECT ); ! Find an object !
if success then
if abs(object.x - player.x) > 2 or abs(object.y - player.y) > 2 then
writeln( "You must get closer!" );
STOP;
endif;
writeln( object.type );
runscript( object.script, "OBJECT", USE );
endif;
if world.density(pointx,pointy) = LOCKED_DOOR then
writeln( "locked door." );
if abs(pointx - player.x) > 1 or abs(pointy - player.y) > 1 then
writeln( "You must be next to it to unlock it!" );
elsif random(2) = 0 then
world.block(pointx,pointy) = world.block(pointx,pointy) - 1;
writeln( "You broke the lock!" );
else
writeln( "You failed to unlock it!" );
endif;
stop;
endif;
goto NOTHING;
:LETTER_V
if group.size > 1 then
writeln( "Who leaves the party?" );
L0 = select( group );
stats;
if player.index = 0 then
writeln( "You can't leave the party!" );
STOP;
endif;
if player.hp = 0 then
writeln( "You leave ", player.name, "'s body to the vultures.." );
elsif player.hp < 2 then
writeln( "You abandon ", player.name, ", who is almost dead.." );
else
writeln( player.name, " leaves the group." );
endif;
LEAVE(player.index);
stats;
else
writeln( "You are alone!" );
endif;
STOP;
:LETTER_W
write( "Wear (or Wield) " );
L0 = select$n( player, WEAPON, ARMOR, RING, AMULET, STAFF, SHIELD );
if L0 >= 0 then
runscript( player.bp.script, "CURRITEM", WEAR );
! Does NOT return !
endif;
stats;
writeln( "nothing .." );
if L0 < -1 then
writeln( "You have no items that you can wear or wield" );
endif;
STOP;
:LETTER_X
if group.vehicle.count then
! We are riding on a vehicle !
curritem = group.vehicle;
runscript( group.vehicle.script, "CURRITEM", EXIT );
else
writeln( "You are already on foot!" );
endif;
STOP;
:LETTER_Y
STOP;
:LETTER_Z
if player.staff.count then
curritem = player.staff;
runscript( player.staff.script, "CURRITEM", invoke );
endif;
STOP;
:NOTHING
if group.x = pointx and group.y = pointy then
writeln( "yourself..?" );
else
writeln( "nothing.." );
endif;
STOP;
:SPACE
writeln( "Pass.." );
goto @0; ! Time Control !
:VIEW_CLICK
! Did we click on ourselves? !
if group.x = pointx and group.y = pointy then
writeln( "Don't do that! It tickles.." );
STOP;
endif;
! First, check the objects !
L2 = locate( object, pointx, pointy );
if success then
if button = 1 then
if abs(pointx - player.x) > 1 or abs(pointy - player.y) > 1 then
writeln( "You can't reach the ", object.type );
STOP;
endif;
if object.type = VEHICLE or object.type = DOOR or
object.type = SIGN or
object.type = CHEST and object.locktype > 0 then
writeln( "Use ", object.type );
runscript( object.script, "OBJECT", USE );
else
writeln( "Get ", object.type );
runscript( object.script, "OBJECT", GET );
endif;
elsif button = 2 then
writeln( "You look at the ", object.type );
if abs(pointx - player.x) > 3 or abs(pointy - player.y) > 3 then
writeln( "You should get closer to look at the ", object.type );
STOP;
endif;
runscript( object.script, "OBJECT", LOOK );
else
writeln( "The middle button has no effect!" );
stop;
endif;
endif;
! Next check the characters !
L2 = locate( npc, pointx, pointy );
if success then
if button = 1 then
if abs(pointx - player.x) > 2 or abs(pointy - player.y) > 2 then
writeln( "You must get nearer for conversation." );
STOP;
endif;
writeln( "Talk to ", npc.type );
runscript( npc.script, "OBJECT", TALK );
elsif button = 2 then
if abs(pointx - player.x) > 3 or abs(pointy - player.y) > 3 then
writeln( "You should get closer to look at the ", npc.type );
STOP;
endif;
writeln( "You look at the ", npc.type );
runscript( npc.script, "OBJECT", LOOK );
else
writeln( "The middle button has no effect!" );
endif;
endif;
if world.density(pointx,pointy) = HIDDEN_DOOR then
if abs(pointx - player.x) > 2 or abs(pointy - player.y) > 2 then
writeln( "You must get closer to the wall." );
else
writeln( "You found a hidden door!" );
world.block(pointx,pointy) = world.block(pointx,pointy) - 1;
endif;
stop;
endif;
if world.density(pointx,pointy) = LOCKED_DOOR then
if abs(pointx - player.x) > 1 or abs(pointy - player.y) > 1 then
writeln( "You must be next to it to unlock it!" );
else
if random(2) = 0 then
world.block(pointx,pointy) = world.block(pointx,pointy) - 1;
writeln( "You broke the lock!" );
else
writeln( "You failed to unlock it!" );
endif;
endif;
stop;
endif;
STOP;
:MENU_CLICK
! I don't do anything with this right now.. !
STOP;
:ICON_CLICK
on pointx goto
LETTER_A, ! Attack !
LETTER_G, ! Get !
LETTER_D, ! Drop !
LETTER_L, ! Look !
LETTER_T, ! Talk !
LETTER_C, ! Camp Out or Sleep !
LETTER_E, ! Enter or Exit through a door !
LETTER_I; ! INVENTORY !
STOP;
:MNAV_CLICK
if pointx = 0 then goto SHOW_GRP; ! Group Stats
elsif pointx = 1 then stats( player.bp ); ! Player's Inventory
elsif pointx = 2 then stats( player.body ); ! Player's Body
elsif pointx = 3 then stats( PREV ); ! Previous Player
elsif pointx = 4 then stats( NEXT ); ! Next Player
elsif pointx = 5 then paint( LARGE ); ! Full Screen Mode
endif;
STOP;
:STAT_CLICK
! Looking at Group, selected an individual !
if pointy < group.size then
GROUP.CURRENT = pointy;
STATS( GROUP.CURRENT ); ! Display INDIVIDUAL statistics !
endif;
STOP;
:CHAR_CLICK
! Looking at Individual (point x), clicked at item)
on pointy goto
SHOW_GRP, ! No item, so go back to showing the GROUP
SHOW_WPN, ! Clicked at weapon being worn (or empty place)
SHOW_SHLD, ! Clicked at shield being worn (or empty place)
SHOW_ARMR, ! Clicked at armor being worn (or empty place)
SHOW_STF, ! Clicked at staff being worn (or empty place)
SHOW_RING, ! Clicked at ring being worn (or empty place)
SHOW_AMULET; ! Clicked at amulet being worn (or emtpy place)
STOP;
:BODY_CLICK
on pointy goto
TEMP_SKIP, ! 0 nothing
SHOW_HND1, ! 1 right hand
SHOW_HND2, ! 2 left hand
SHOW_ARMR, ! 3 torso
TEMP_SKIP, ! 4 waist
TEMP_SKIP, ! 5 legs
TEMP_SKIP, ! 6 feet
TEMP_SKIP, ! 7 hat
SHOW_AMULET, ! 8 neck
SHOW_RING, ! 9 right ring
TEMP_SKIP; !10 left ring
:TEMP_SKIP
STOP;
:SHOW_HND1
if player.weapon.count goto SHOW_WPN;
goto SHOW_STF;
STOP;
:SHOW_HND2
if player.shield.count goto SHOW_SHLD;
goto SHOW_STF;
STOP;
:PACK_CLICK
if pointy >= 0 then
setbp( player, pointy );
gosub DO_BP_ITEM;
endif;
STOP;
:SHOW_GRP
STATS( group ); ! Display GROUP statistics !
STOP;
:SHOW_WPN
if player.weapon.count then
curritem = player.weapon;
gosub DO_WORN_ITEM;
endif;
STOP;
:SHOW_SHLD
if player.shield.count then
curritem = player.shield;
gosub DO_WORN_ITEM;
endif;
STOP;
:SHOW_ARMR
if player.armor.count then
curritem = player.armor;
gosub DO_WORN_ITEM;
endif;
STOP;
:SHOW_STF
if player.staff.count then
curritem = player.staff;
gosub DO_WORN_ITEM;
endif;
STOP;
:SHOW_RING
if player.ring.count then
curritem = player.ring;
gosub DO_WORN_ITEM;
endif;
STOP;
:SHOW_AMULET
if player.amulet.count then
curritem = player.amulet;
gosub DO_WORN_ITEM;
endif;
STOP;
:DO_WORN_ITEM
if button = 1 then
writeln( "Remove ", curritem.type, ".." );
runscript( curritem.script, "CURRITEM", REMOVE );
elsif button = 2 then
writeln( "Look at ", curritem.type );
runscript( curritem.script, "CURRITEM", LOOK );
endif;
return;
:DO_BP_ITEM
if player.bp.count then
curritem = player.bp;
if button = 1 then
if curritem.type = WEAPON or curritem.type = ARMOR or
curritem.type = RING or curritem.type = AMULET or
curritem.type = SHIELD or curritem.type = STAFF then
writeln( "Wear/Wield ", curritem.type, ".." );
runscript( curritem.script, "CURRITEM", WEAR );
else
writeln( "Use ", curritem.type, ".." );
runscript( curritem.script, "CURRITEM", USE );
endif;
elsif button = 2 then
writeln( "Look at ", curritem.type );
runscript( curritem.script, "CURRITEM", LOOK );
endif;
endif;
return;
!---------------------------------------------------------------------------!
!---------------------------------------------------------------------------!
!---------------------------------------------------------------------------!
!---------------------------------------------------------------------------!
!---------------------------------------------------------------------------!
!
! SUBROUTINE: HEAL_HP
!
! Heal the players with the passage of time
!
:HEAL_HP
! alive and not sick !
if player.hp > 0 and not player.poisoned then
dec( player.energy );
if player.energy <= 0 then
if group.food > 0 then
dec( group.food );
player.energy = 255;
else
writeln( player.name, " goes hungry!" );
return;
endif;
endif;
if player.hp < player.mhp then
inc( player.hp );
endif;
endif;
return;
!
! SUBROUTINE: HEAL_PWR
!
! Restore magic points withthe passage of time..
!
:HEAL_PWR
if player.hp > 0 and player.energy > 0 and player.pwr < player.mpwr then
inc( player.pwr );
if player.class = ELF and player.pwr < player.mpwr then
inc( player.pwr ); ! Do elves faster.. !
endif;
endif;
return;
!
! SUBROUTINE to create a Random Monster
!
:NEWMONSTER
! Try to find a position for the monster up to 8 times..
for L3 = 1 to 8 do
L0 = group.x + random(8) - 4;
L1 = group.y + random(8) - 4;
if L0 < 0 then L0 = 0; endif;
if L1 < 0 then L1 = 0; endif;
if L0 >= world.x then L0 = world.x - 1; endif;
if L1 >= world.y then L1 = world.y - 1; endif;
if L0 <> player.x or L1 <> player.y then
L2 = world.density(L0,L1);
if L2 = FLAT or L2 = ROUGH or L2 = VERY_ROUGH or L2 = SWAMP or L2 = DESERT then
! Create a LAND-BASED monster !
L2 = random(3); ! Small, Medium or Large (0-2) !
L3 = random(L2+3); ! Select a graphics block for that size (0-4) !
if world.type = DUNGEON then
L4 = DEFCAVEBLK( L3 ); ! Leader !
L5 = DEFCAVEBLK( random(L3+1) ); ! Follower !
L6 = CAVE_MONSTER;
elsif world.type = HAUNTED then
L4 = DEFSPOOKBLK( L3 ); ! Leader !
L5 = DEFSPOOKBLK( random(L3+1) ); ! Follower !
L6 = SPOOK_MONSTER;
else
! OUTDOORS or ARENA !
L4 = DEFLANDBLK( L3 ); ! Leader !
L5 = DEFLANDBLK( random(L3+1) ); ! Follower !
L6 = LAND_MONSTER;
endif;
goto DOIT;
elsif L2 = DEEP_WATER then
! Create a WATER-BOUND monster !
L2 = random(3); ! Small, Medium, Large (0-2) !
if random(5) = 0 then ! Pirate Ship (SPECIAL CASE) !
L4 = DEFWATERBLK(4); ! Fifth water monster is a ship !
L5 = DEFWATERBLK(4); ! Followers are ships also !
else
L3 = random(L2+2); ! Select a graphics block for that size (0-3) !
L4 = DEFWATERBLK( L3 ); ! Leader !
L5 = DEFWATERBLK( random(L3+1) ); ! Follower !
endif;
L6 = WATER_MONSTER;
goto DOIT;
endif;
endif;
endfor;
return; ! Tried 8 Times, give up !
:DOIT
new(npc,L0,L1,L4);
npc.type = HOSTILE; ! NPC Type
npc.stats = defstat(L2); ! Statistics Record
npc.block2 = L5; ! Followers (if any)
npc.class = L6; ! Monster Class
! Gold carried
if world.type = ARENA then
npc.value = random(50)+1; ! Very little money (Up to 5 gold pieces) !
else
npc.value = 0;
endif;
!
! # of monsters in the group. The formula is based on L2 (monster size).
! If small (L2=0), then # = random( group.size + 6 ) + 1
! If medium (L2=1), then # = random( group.size + 3 ) + 1
! if large (L2=2), then # = random( group.size ) + 1
npc.count = random( group.size + (2 - L2) * 3 ) + 1;
L254 = TRUE; ! Monster has been created !
voice( "ALERT", 1000 );
return;
!
! This SUBROUTINE will hit every player in the group by using the
! subroutine HITPLAYER.
!
:HITGROUP
foreach player do
gosub HITPLAYER;
endfor;
return;
!
! This SUBROUTINE will decrement the hit points of the current
! group member. It checks to see if the player has died or lost
! consciousnes. The variable S0 contains the reason for the hit.
!
:HITPLAYER
if player.hp > 0 then
dec( player.hp );
if player.hp = 0 then
writeln( player.name, " has died of ", s0, "!" );
elsif player.hp = 1 then
writeln( player.name, " has fainted from ", s0, "!" );
else
writeln( player.name, " weakens!" );
endif;
endif;
return;
!------------------------------------------------------------------------!
!
! SUBROUTINE: M1_INVOKE
!
! Type 1 Magic - Affects the person invoking the magic..
!
! This code is equivalent to the one in OBJECT.SCR. When resting,
! rings and amulets that have magical properties will re-invoke their
! effect when you wake up.
!
!------------------------------------------------------------------------!
:M1_INVOKE
!------------------------------------------------------------------------!
if curritem.cursed then
if curritem.permanent then
L0 = msgbox( ERROR, 1, "Ok", "WARNING: Cursed Item with PERMANENT effect are not recommended!" );
curritem.permanent = FALSE;
endif;
endif;
if curritem.charges < 255 then
dec(curritem.charges); ! 255 means forever !
endif;
on curritem.class goto
M1_NONE, M1_CURE, M1_HEAL, M1_POISON, M1_RESTORE,
M1_STR, M1_DEX, M1_SPD, M1_AIM, M1_AC,
M1_HP, M1_IQ, M1_PWR;
:M1_NONE
return;
:M1_CURE
if player.poisoned then
player.poisoned = 0;
writeln( player.name, " is now cured." );
endif;
return;
:M1_HEAL
if player.hp > 0 and player.hp < player.mhp then
if curritem.units > 0 then
L(0) = curritem.units; ! always heals the same points !
else
L(0) = random(player.mhp - player.hp)+1; ! heal a random number of points !
endif;
if player.hp + L(0) < player.mhp then
writeln( player.name, " heals ", L(0), " hit points.." );
inc( player.hp, L(0) );
else
writeln( player.name, " has been completely healed!" );
player.hp = player.mhp;
endif;
endif;
return;
:M1_POISON
if NOT player.poisoned then
player.poisoned = TRUE;
writeln( player.name, " is poisoned!" );
endif;
return;
:M1_RESTORE
if player.hp < player.mhp then
player.hp = player.mhp;
writeln( player.name, " is completely healed!" );
endif;
return;
:M1_STR
if curritem.cursed then
player.str = 0;
else
inc( player.str, curritem.units );
if curritem.permanent then
inc( player.mstr, curritem.units );
endif;
writeln( player.name, "'s strength increased by ", curritem.units, "!" );
endif;
return;
:M1_DEX
if curritem.cursed then
player.dex = 0;
else
inc( player.dex, curritem.units );
if curritem.permanent then
inc( player.mdex, curritem.units );
endif;
writeln( player.name, "'s dexterity increased by ", curritem.units, "!" );
endif;
return;
:M1_SPD
if curritem.cursed then
player.spd = 0;
else
inc( player.spd, curritem.units );
if curritem.permanent then
inc( player.mspd, curritem.units );
endif;
writeln( player.name, "'s speed increased by ", curritem.units, "!" );
endif;
return;
:M1_AIM
if curritem.cursed then
player.aim = 0;
else
inc( player.aim, curritem.units );
if curritem.permanent then
inc( player.maim, curritem.units );
endif;
writeln( player.name, "'s aim increased by ", curritem.units, "!" );
endif;
return;
:M1_AC
if curritem.cursed then
player.ac = 0;
else
inc( player.ac, curritem.units );
if curritem.permanent then
inc( player.mac, curritem.units );
endif;
writeln( player.name, "'s armor class increased by ", curritem.units, "!" );
endif;
return;
:M1_HP
if curritem.cursed then
player.hp = player.hp / 3 + 1;
else
inc( player.hp, curritem.units );
if curritem.permanent then
inc( player.mhp, curritem.units );
endif;
writeln( player.name, "'s hit points increased by ", curritem.units, "!" );
endif;
return;
:M1_IQ
if curritem.cursed then
player.iq = 0;
else
inc( player.iq, curritem.units );
if curritem.permanent then
inc( player.miq, curritem.units );
endif;
writeln( player.name, "'s i.q. increased by ", curritem.units, "!" );
endif;
return;
:M1_PWR
if player.class = ELF or player.class = WIZARD then
if curritem.cursed then
player.pwr = 0;
else
inc( player.pwr, curritem.units );
if curritem.permanent then
inc( player.mpwr, curritem.units );
endif;
writeln( player.name, "'s power increased by ", curritem.units, "!" );
endif;
else
write( player.name, " has a headache all night long.." );
if player.hp < 3 then
writeln( " and dies!" );
player.hp = 0;
else
writeln;
dec( player.hp, 2 );
endif;
endif;
return;
!-----------------------------------------------------------------------!
! Allow ONE minute of time to go bye in the game's clock !
!-----------------------------------------------------------------------!
:CLOCK_TICK
if minute < MinutesInAnHour - 1 then
inc( minute );
else
minute = 0;
if hour < HoursInADay - 1 then
inc( hour );
else
hour = 0;
if day < DaysInAMonth - 1 then
inc( day );
else
day = 0;
if month < MonthsInAYear - 1 then
inc( month );
else
month = 0;
inc( year );
endif;
endif;
if hour = sunrise then
writeln( "The sun rises in the east. " );
! gosub DAYNIGHT;
elsif hour = sunset then
writeln( "The sun sets in the west. " );
! gosub DAYNIGHT;
endif;
endif;
endif;
return;
!-----------------------------------------------------------------------!
! Print the current time !
!-----------------------------------------------------------------------!
:CLOCK_PRINT
L1 = HoursInADay / 2; ! Noon !
if hour > L1 then
if minute = 0 then
writeln( "It's ", hour - L1, "pm" );
elsif minute < 10 then
writeln( "It's ", hour - L1, ":0", minute, "pm" );
else
writeln( "It's ", hour - L1, ":", minute, "pm" );
endif;
elsif hour = 0 then
writeln( "It's midnight" );
elsif hour = L1 then
writeln( "It's noon" );
else
if minute = 0 then
writeln( "It's ", hour, "am" );
elsif minute < 10 then
writeln( "It's ", hour, ":0", minute, "am" );
else
writeln( "It's ", hour, ":", minute, "am" );
endif;
endif;
return;
!
!:DAYNIGHT
!
! Ideally, we should reflect sunrise and sunset by some visual
! change in the game. For example:
!
! If we wanted to create a "daylight"/"night-type" effect, we have
! two options. One, create two landscape sets that are identical
! except one uses darker colors (you really need 256 colors for
! this), as follows:
!
! if world.type = OUTDOORS then
! if hour = sunrise then
! world.landscape = 0;
! elsif hour = sunset then
! world.landscape = 1;
! endif;
! endif;
! return;
!
! The second one is to have a second PALETTE of colors, which
! are darker than the standard palette. You can then just
! change the palette
!
! if hours = sunset then loadpalette( "NIGHT.PAL" );
! elsif hour = sunrise then loadpalette( "DAY.PAL" );
! return;
!
! However, I did not implement 'loadpalette()' yet, so this last
! option is not possible right now. :)
!
!------------------------------------------------------
! Attack an NPC
!------------------------------------------------------
:ATTACK_NPC
! L3 contains distance to current npc per LOCATE command !
! L4 the weapon class (blunt, missile, etc)
! L5 the range (distance) you can reach with this weapon
! L6 is non-zero if type of ammo that is needed by the weapon
! L7 is the damage points done
if player.weapon.count then
L4 = player.weapon.class;
L5 = player.weapon.range;
L6 = player.weapon.ammoneeded;
L7 = player.weapon.damage;
else
L4 = BLUNT;
L5 = 1;
L6 = 0;
L7 = 1;
endif;
if L4 = MISSILE then
for L10 = 0 to 15 do
setbp( player, L10 );
if player.bp.count then
if player.bp.type = AMMO and player.bp.ammotype = L6 then
if player.bp.count < 255 then
dec(player.bp.count); ! Count of 255 means it never ends? !
endif;
L5 = max( L5, player.bp.range ); ! Use ammo's range if higher !
inc( L7, player.bp.damage ); ! If ammunition causes extra damage !
L6 = L10; ! Keep AMMO's BP here !
goto FOUND_AMMO;
endif;
endif;
endfor;
writeln( "Out of ammo! Using hands!" );
L4 = BLUNT;
L5 = 1;
L6 = 0;
L7 = 1;
:FOUND_AMMO
endif;
if L5 < L3 then
writeln( "You have to get closer!" );
stop;
endif;
! HERE I COULD 'RANDOMIZE' THE DAMAGE, BUT I'LL LET IT BE CONSTANT FOR NOW !
! For contact weapons, STRENGTH increases damage !
if L4 = BLUNT or L4 = EDGED then
inc( L7, adjustments( player.str ) );
endif;
! Now, we have to figure out if we missed !
if L4 = MISSILE then
! For missile weapon, hit 5 out of 10, adjusted by AIM !
if random( 10 ) + adjustments( player.aim ) < 5 then
writeln( player.name, " missed.." );
voice( "BadAim", 1000 );
else
gosub HIT_NPC;
endif;
else
! For non-missile weapon, hit 7 out of 10 adjusted up by the
! player's dexterity and down by the NPC's dexterity
if random(10) + adjustments(player.dex) - adjustments(npc.dex) < 3 then
writeln( player.name, " missed.." );
voice( "Swish", 1000 );
else
gosub HIT_NPC;
endif;
endif;
stop;
:HIT_NPC
L7 = max( L7, 1 ); ! At least one HP of damage !
if npc.hp > 1 and npc.ac > 0 then ! Armor Class protects the NPC !
L8 = random( npc.ac+1 ); ! Absorb 0 to npc.ac damage points !
if L8 >= L7 then
writeln( npc.type, "'s armor absorbs the impact!" );
voice( "Clank", 1000 );
return;
endif;
dec( L7, L8 ); ! Reduce damage by L8 amount !
endif;
! Fast PLAYERS get to hit more than once !
if player.spd > npc.spd then
L9 = (player.spd - npc.spd) / 10 + 1;
else
L9 = 1;
endif;
L10 = L9; ! Original # of Moves !
while L9 > 0 and npc.count do
if npc.hp > L7 then
if L9 <> L10 then
write( npc.type, " hit - again!" );
else
write( npc.type, " hit!" );
endif;
dec( npc.hp, L7 );
on random(3) gosub :V1, :V2, :V3;
else
write( npc.type, " killed!" );
voice( "YouKill", 1000 );
L7 = npc.hp;
! Now is the perfect time to GENERATE RANDOM TREASURE !
gosub TREASURE;
npc.count = 0; ! Actually Kill the NPC !
endif;
writeln( " (", L7, " points)" );
inc( player.exp, L7 );
dec(L9);
endwhile;
return;
:V1 voice( "Argh", 1000 ); return;
:V2 voice( "Ouch", 1000 ); return;
:V3 voice( "Whoosh", 1000 ); return;
!------------------------------------
:TREASURE
!------------------------------------
! Generate random treasure
! First, leave the contents of the NPCs backpack..
foreach npc.bp do
drop( npc.bp, -npc.count, npc.x, npc.y ); ! Drop a copy of this item
endfor;
! Now generate a random treasure
on random(4) goto GT_NONE, GT_GOLD, GT_CHEST, GT_SPECIAL;
:GT_NONE
return;
:GT_GOLD
new( object, npc.x, npc.y, GOLDSACK );
object.weight = random( player.mhp ) + 1;
object.value = object.weight * 10;
return;
:GT_CHEST
new( object, npc.x, npc.y, CHEST );
object.class = NORMAL_CHEST;
object.weight = random( player.mhp ) + 1;
object.value = object.weight * 10;
object.locktype = random(2); ! 0=None, 1+ = Key !
object.traptype = random(3); ! 0=None, 1=Poison, 2+ = Bomb !
return;
:GT_SPECIAL
! AMULET=5,RING=6,POTION=7,SCROLL=8,STAFF=9
new( object, npc.x, npc.y, AMULET + random(5) );
if object.type = SCROLL or object.type = STAFF then ! SCROLL or STAFF !
object.class = random(15)+1; ! See OBJECT CLASS in DCCTOKEN.DAT !
else
object.class = random(12)+1; ! See OBJECT CLASS in DCCTOKEN.DAT !
endif;
object.weight = 1;
if object.type = RING or object.type = AMULET or object.type = STAFF then
object.charges = random( player.level ) + 1;
endif;
if object.type = RING or object.type = AMULET or object.type = POTION then
object.units = random( player.mhp ) + 1;
object.permanent = (random(100) = 0); ! One out of 100 !
endif;
if object.permanent then
object.value = 1000;
object.weight = 2;
else
object.value = 10;
endif;
return;
!------------------------------------
:NEW_LEVEL
!------------------------------------
L10 = 1; ! Start with level 1
L11 = 200; ! Next level is at 200
while L11 < player.exp do
inc( L11, L11 ); ! Each level is TWICE as much as the previous one !
inc( L10, 1 );
endwhile;
if L10 > player.level then ! New Level !
L12 = random( player.level ) + 1; ! First, give some hit points !
write( "New level! ", player.name, " gained ", L12, "hp " );
inc( player.level );
inc( player.mhp, L12 ); ! Permanent Increase !
inc( player.hp, L12 ); ! Reflect the new HP immediatly !
! Now increase one ore more attributes depending on the class !
L12 = random(player.level + 1) + 1; ! Start with this many points !
if L12 > 5 then
L12 = random(10); ! Make more than 5 points 'unlikely' but possible
endif;
on player.class goto
:EX_HUMAN,
:EX_ELF,
:EX_DWARF,
:EX_WIZARD,
:EX_ARCHER,
:EX_FIGHTER;
endif;
return; ! No new level !
:EX_HUMAN ! Humans and 'unknown'
inc( player.mstr, L12 );
writeln( "and ", L12, " str." );
return;
:EX_ELF
inc( player.miq, L12 + L12 ); ! Elf gains intelligence twice as fast !
writeln( "and ", L12, " iq." );
return;
:EX_DWARF
L13 = random(L12);
inc( player.mstr, L12 - L13 ); ! Dwarf gains some strength !
inc( player.mdex, L13 ); ! and some dexterity !
writeln( ", ", L12 - L13, " str and ", L13, " dex." );
return;
:EX_WIZARD
inc( player.miq, L12 ); ! Wizards gain intelligence !
writeln( "and ", L12, " iq." );
return;
:EX_ARCHER
L13 = random(L12);
inc( player.maim, L12 - L13 ); ! Dwarf gains some aim !
inc( player.mspd, L13 ); ! and some speed !
writeln( ", ", L12 - L13, " aim and ", L13, " speed." );
return;
:EX_FIGHTER
inc( L12, random(L12) ); ! Fighters gain strength more quickly !
inc( player.mstr, L12 );
writeln( "and ", L12, " str." );
return;
!
! MOVING THE CHARACTERS
!
:MOVE_UP
L3 = 0; L4 = -1; goto DO_MOVE;
:MOVE_DN
L3 = 0; L4 = 1; goto DO_MOVE;
:MOVE_LF
L3 = -1; L4 = 0; goto DO_MOVE;
:MOVE_RT
L3 = 1; L4 = 0; goto DO_MOVE;
:MOVE_UL
L3 = -1; L4 = -1; goto DO_MOVE;
:MOVE_DL
L3 = -1; L4 = 1; goto DO_MOVE;
:MOVE_UR
L3 = 1; L4 = -1; goto DO_MOVE;
:MOVE_DR
L3 = 1; L4 = 1; goto DO_MOVE;
:DO_MOVE
L0 = player.x + L3;
L1 = player.y + L4;
if world.wrap_around then
if L0 < 0 then
gosub NOTFIGHTING;
L0 = world.x - 1;
elsif L0 >= world.x then
gosub NOTFIGHTING;
L0 = 0;
endif;
if L1 < 0 then
gosub NOTFIGHTING;
L1 = world.y - 1;
elsif L1 >= world.y then
gosub NOTFIGHTING;
L1 = 0;
endif;
else
if L0 < 0 or L0 >= world.x or L1 < 0 or L1 >= world.y then
gosub NOTFIGHTING;
s0 = swriteln( "Do you want to leave ", world.name, "?" );
L0 = msgbox( QUESTION, 2, "Yes", "No", S0 );
if L0 = 0 then
world.door = world.edge_door;
runscript( WORLD, "WORLDDEF", EXIT );
!
! NOTE: We could just run "enter( world.edge_door );" instead
! of the above two lines. The difference is that when you
! run ENTER( door ), the driver does NOT call the @EXIT
! routine in the current world. A minor but important
! difference. The reason for this, is that the behaviour of
! ENTERING A WORLD (i.e. load the world, call script at @GET,
! call script at @ENTER) is a feature of the driver, but
! the @EXIT entry point is handled entirely by the scripts
! themselves. If you don't want to take any action when you
! exit a world, you can change the above two lines to a
! simple call to the ENTER() function.
!
endif;
stats;
STOP;
endif;
endif;
!
!
! No. Do a generic check for objects and landscaping
! density.
!
! Note L0, L1 are already set to the correct X/Y location
! L2 needs to be 0 for NPC checking, 1 for PLAYER checking
L2 = 1;
gosub CHK_A_MOVE; ! Move player, current NPC not important !
if not L2 then
if s0 <> "" then
writeln(s0);
endif;
STOP;
endif;
! Go Ahead and Move
if fighting then
if group.vehicle.count then ! Inside a vehicle !
group.x = L0; group.y = L1;
else
if group.size > 1 then
! Must check that we are not standing in another
! player's toes..
L2 = player.index; ! Store Current Player Index
S0 = player.name; ! Store player's name
foreach player do
if player.index <> L2 and player.hp > 0 then
if L0 = player.x and L1 = player.y then
writeln( S0, " bumps into ", player.name );
player.index = L2; ! Restore Index !
STOP;
endif;
endif;
endfor;
player.index = L2; ! Restore Index !
endif;
! Go ahead and move !
player.x = L0; player.y = L1;
endif;
else
group.x = L0; group.y = L1;
! Check for Trap doors !
if L0 > 0 and L1 > 0 then
for L5 = 0 to 31 do
if L0 = world.doorx(L5) and L1 = world.doory(L5) then
if world.trapdoorswitch(L5) then
world.door = L5; ! Use this door !
runscript( WORLD, "WORLDDEF", EXIT );
endif;
endif;
endfor;
endif;
endif;
STOP;
:NOTFIGHTING
if fighting then
writeln( "You can't leave during a fight.." );
stop;
endif;
return;
:FKEY1
! Help !
view_pcx( "ANYFRAME.PCX" );
setframe( "ANYFRAME.PCX", 20, 20, 20, 20 );
pwriteln( "The following commands are defined:" );
pwriteln;
pwriteln( "A)ttack, ", "C)amp, ", "D)rop, ", "E)nter, ", "G)et, ",
"I)nventory, ", "L)ook, ", "iN)voike, ", "Q)uaff (eat or drink), ",
"R)emove, ", "S)pell, ", "T)alk, ", "U)se, ", "V)acate, ",
"W)ield/Wear, ", "eX)it, ", "Z)ap (with staff)" );
pwriteln;
pwriteln( "You may also use:" );
pwriteln( "F1=Help, ", "F2=Save, ", "F3=Sound, ", "F4=Restore, ",
"F6=Restart, ", "F10=Exit", " and <ALT>V to set the VOLUME" );
pwriteln;
pwriteln( "Press [SPACE] to continue" );
pause;
paint( window );
STOP;
:FKEY2
L0 = getnum( "Save in what slot?", 0, 999 );
if L0 >= 0 then
save( L0 );
stop;
endif;
continue;
:FKEY3
sound = not sound;
if sound then
writeln( "Sound is now on!" );
else
writeln( "Sound is now off!" );
endif;
stop;
:ALT_V
L3 = select( "Low (6)", "Medium (9)", "Normal (12)", "High (15)" );
if L3 >= 0 then
L3 = L3 * 3 + 6;
VOLUME( L3, L3 );
voice( "WAKECALL", 1000 );
endif;
stop;
:FKEY4
L0 = getnum( "Restore from what slot?", 1, 999 );
if L0 > 0 then
restore( L0 );
writeln( "RESTORE OF SLOT ", L0, " FAILED!" );
endif;
stop;
:FKEY5
savepcx( "SCRNSAVE.PCX" );
stop;
:FKEY6
L0 = msgbox( QUESTION, 2, "Yes", "No", "Do you really want to RESTART?" );
if L0 = 0 then
restart;
writeln( "RESTART FAILED!" );
endif;
stats;
stop;
:FKEY7
foreach player do
player.level = 10;
endfor;
stop;
:FKEY8
if split then paint( large ); else paint( small ); endif;
stop;
:FKEY9
runscript( "test", 0 );
stop;
:FKEY10
if fighting then
writeln( "Press ESCape to stop the fight, then F10 to exit!" );
stop;
endif;
writeln( "See you later..." );
save(0);
end_game;
!
! Routine to verify if a location can be occupied by
! a character (player or NPC).
!
! L0 = x, L1 = y, L2 = 1/player, 0/npc
! L3 = delta on X, L4=delta on Y for guard checking
!
! Returns L2 = NO (0) or L2 = YES (1)
!
:CHK_A_MOVE
S0 = ""; ! No Return Message to start with .. !
if L2 then ! player !
L21 = group.vehicle.class;
elsif npc.class = WATER_MONSTER then ! Water Monster !
L21 = BOAT;
else
L21 = WALKING;
endif;
L2 = NO;
! Check for another character in the way !
L20 = locate( npc, L0, L1 );
if L20 >= 0 then
s0 = "There is someone standing in your way!";
return;
endif;
! Check for GUARDS !
! NOTE: We could just check every NPC with a loop as follows:
! foreach NPC do
! if npc.type = GUARD then
! if abs(npc.x - L0) < 2 and abs(npc.y - L1) < 2 then
! S0 = "There is a GUARD there!";
! return;
! endif;
! endif;
! endfor;
! But the loop might cause unnecesary disk accesses if you have
! a large number of NPCs, because the backpacks of the NPCs are
! kept on disk and only a small number are kept in memory.
! An alternative is to use the VISIBLE qualification as follows:
! foreach VISIBLE npc do
! ...
! endfor;
! This will limit the number of NPCs being scanned, but it is
! still not the best way.
! The following is better. It uses the LOCATE command to search
! for guards at specific X/Y locations, thus it only loads an
! NPC's backpack if there IS an NPC at the x/y location.
!
! -> MUCH BETTER:
L2 = YES; ! Assume OK !
if L3 then ! Moving on X !
L20 = locate( npc, L0+L3, L1 );
if success then gosub check_guard; endif;
L20 = locate( npc, L0+L3, L1+1 );
if success then gosub check_guard; endif;
L20 = locate( npc, L0+L3, L1-1 );
if success then gosub check_guard; endif;
endif;
if L4 then ! Moving on Y !
L20 = locate( npc, L0 , L1+L4 );
if success then gosub check_guard; endif;
L20 = locate( npc, L0+1, L1+L4 );
if success then gosub check_guard; endif;
L20 = locate( npc, L0-1, L1+L4 );
if success then gosub check_guard; endif;
endif;
if not L2 then
return;
endif;
L2 = NO; ! Keep Checking !
! Check for an OBJECT in the way !
L20 = locate( object, L0, L1 );
if L20 >= 0 then ! Yes, see if we can step
while object.x = L0 and object.y = L1 do
! Check for locked doors
if object.type = DOOR and object.locktype > 0 then
S0 = "The door is locked!";
return;
endif;
! Check for fences and things, both of which we should not
! be able to walk over.
if object.type = FENCE or object.type = THING then
s0 = swriteln("There is a ",object.name," in your way");
return;
endif;
if object.index = 0 goto XDONE;
dec( object.index );
if failure goto XDONE;
endwhile;
endif;
:XDONE ! No blocking objects...
!
! Now check the world's density and see if we can walk over it
! considering the type of landscape and the vehicle (or monster
! type) if any.
!
L20 = world.density(L0,L1);
if L20 = WALL or L20 = LOCKED_DOOR or L20 = HIDDEN_DOOR then
s0 = "You can't go there.";
return;
endif;
on L21 goto
CHK_WALK, CHK_MOUNT, CHK_ATV, CHK_LFLY, CHK_MFLY, CHK_HFLY, CHK_RAFT, CHK_BOAT;
! Anything else, don't allow the move !
s0 = "You can't go there.";
return;
! -- ON WATER -- !
:CHK_RAFT
if L20 = LOW_WATER or L20 = ROUGH_WATER goto GO_AHEAD;
if L20 = DEEP_WATER then
s0 = "You can't go in deep water.";
else
s0 = "No swiming allowed here.";
endif;
return;
:CHK_BOAT
if L20 = DEEP_WATER goto GO_AHEAD;
if L20 = LOW_WATER or L20 = ROUGH_WATER then
s0 = "The water is not deep enough.";
else
s0 = "You can't go there.";
endif;
return;
! -- BY AIR -- !
:CHK_LFLY
if L20 = DEEP_WATER then
s0 = "You can't fly over deep water.";
return;
endif;
! Drop Through !
:CHK_MFLY
if L20 = VERY_HIGH then
s0 = "You can't fly high enough.";
return;
endif;
! Drop Through !
:CHK_HFLY
goto GO_AHEAD;
! -- ON FOOT -- !
:CHK_WALK
if L20 = FLAT or L20 = DESERT or L20 = SWAMP goto GO_AHEAD;
if L20 = ROUGH and random(3) <> 0 or
L20 = VERY_ROUGH and random(3) = 0 goto GO_AHEAD;
! Anything else, don't allow the move !
if L20 = ROUGH or L20 = VERY_ROUGH then
S0 = "The terrain is very rough.";
else
S0 = "You can't go there.";
endif;
return;
:CHK_MOUNT
if L20 = FLAT or
L20 = ROUGH or
L20 = VERY_ROUGH and random(3) <> 0 then ! 2 out of 3 !
goto GO_AHEAD;
endif;
if L20 = VERY_ROUGH then
S0 = "The terrain is very rough.";
endif;
return;
:CHK_ATV
if L20 = FLAT or L20 = ROUGH or L20 = VERY_ROUGH or L20 = LOW_WATER then
goto GO_AHEAD; ! All Terrain Vehicle !
endif;
! Anything else, don't allow the move !
S0 = "You can't go there.";
return;
:GO_AHEAD
! Go Ahead and Move
L2 = YES;
return;
:CHECK_GUARD
!
! From GUARD.SCR, npc.v1 = 1 means you have given the password to the
! guard, so you can pass. npc.v1 = 2 means you have given a BRIBE to
! the guard, so you can also pass.
!
if npc.type = GUARD and npc.v1 = 0 then
s0 = "There is a GUARD there!";
L2 = NO; ! Can't Pass !
endif;
return;